package com.pansky.crm.filter;

import com.pansky.crm.config.redis.RedisBean;
import com.pansky.crm.constants.CommonConstant;
import com.pansky.crm.util.TokenUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticationFilter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Slf4j
public class ClientShiroFilter extends AuthenticationFilter {

    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        if (httpRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            System.out.println("httpRequest.getHeader(\"Origin\") is :" + httpRequest.getHeader("Origin"));
            httpResponse.setHeader("Access-control-Allow-Origin", httpRequest.getHeader("Origin"));
            httpResponse.setHeader("Access-Control-Allow-Methods", httpRequest.getMethod());
            httpResponse.setHeader("Access-Control-Allow-Headers", httpRequest.getHeader("Access-Control-Request-Headers"));
            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setStatus(HttpStatus.OK.value());
            return false;
        }
        return super.preHandle(request, response);
    }

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpServletRequest request = (HttpServletRequest) servletRequest;

        String ajax = request.getHeader("x-requested-with");
        if (null==ajax) {
            log.info("=====不是ajax");
            response.sendRedirect("/login");
        }else {
            log.info("=====是ajax"+ajax);
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().write("访问有问题");
        }
        return false;
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        RedisBean redisBean = getBean(RedisBean.class, request);
        if ("OPTIONS".equals(request.getMethod())){
            response.setStatus(204);
            log.info("OPTIONS 放行");
            return true;
        }
        String token = request.getHeader(TokenUtil.TOKEN_HEARD);
        log.info("================"+token);
        if (null == token||"".equals(token)) {
            log.error("-------------------token为空");
            return false;
        }
        //验证token的真实性
        try {
            Claims body = TokenUtil.getTokenBody(token);
            if (isEqualToken(redisBean, token, body)) {
                log.error("-------------------传入token和redis中token不一致");
                return false;
            }
            if (null == redisBean.get("LOGIN_TOKEN:" + body.getSubject())) {
                redisBean.set("LOGIN_TOKEN:" + body.getSubject(), redisBean.get("LOGIN_REFRESH_TOKEN:" + body.getSubject()), redisBean.getExpire("LOGIN_REFRESH_TOKEN:" + body.getSubject()));
            }
            Date date = body.getExpiration();
            if ((date.getTime() - new Date().getTime()) <= CommonConstant.CHECK_EXPIRE_TIME_MILLISECOND) {
                String refreshToken = TokenUtil.refreshTokenExpired(token);
                log.info("refreshToken is :{}", refreshToken);
                redisBean.addKey("LOGIN_REFRESH_TOKEN:" + body.getSubject(), refreshToken, CommonConstant.EXPIRE_TIME_SECOND, TimeUnit.SECONDS);
                response.setHeader("Authorization", refreshToken);
                response.setHeader("Access-Control-Expose-Headers", "Authorization");
            }
            Subject subject = SecurityUtils.getSubject();
            System.out.println("subject session : " + subject.getSession().getId());
            PrincipalCollection principals = subject.getPrincipals();
            System.out.println("principals is " + principals);
            boolean permitted = subject.isPermitted(request.getServletPath());
            System.out.println("permitted is " + permitted);
            return permitted;
        } catch (Exception e) {
            log.error("----------------token有问题:", e);
            return false;
        }
    }

    @Override
    public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)
            throws Exception {
        HttpServletRequest req = (HttpServletRequest)request;
        if(req.getMethod().equals(RequestMethod.OPTIONS.name())){
            return true;
        }
        return super.onPreHandle(request, response, mappedValue);
    }

    private boolean isEqualToken(RedisBean redisBean, String token, Claims body) {
        return !token.equals(redisBean.get("LOGIN_TOKEN:" + body.getSubject())) &&
                !token.equals(redisBean.get("LOGIN_REFRESH_TOKEN:" + body.getSubject()));
    }

    public <T> T getBean(Class<T> clazz,HttpServletRequest request){
        WebApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
        return applicationContext.getBean(clazz);
    }
}
